#include "PTOParser.h"

#include <fstream> //for ifstream -> file input
#include <iostream> 
#include <sstream> //for stringstream
#include <string>
#include <deque>

#include "../utils/Output.h"

using std::cout;
using std::endl;

PTOParser::PTOParser()
{
}

PTOParser::~PTOParser()
{
}

errorCodes::errorCode PTOParser::parse(std::string inputFileName){

	std::ifstream inputFile(inputFileName.c_str());
	
	std::string currentLine;
	
	std::string currentToken;
	
	
	std::deque<ImageParams> imageParams;

	std::getline(inputFile, currentLine);
	while(!inputFile.eof() && currentLine.find("# image lines") == std::string::npos){

		std::cout << currentLine << std::endl;
		
		
		std::getline(inputFile, currentLine);
	}
	std::cout << "found images" << std::endl;
	
	while(!inputFile.eof() && currentLine.find("# control points") == std::string::npos){
		if (currentLine.find("#-hugin  cropFactor=1") != std::string::npos){
			cout << "disregarding " << currentLine << endl;
			//disregard
		} else if (currentLine.length() > 0 && currentLine.at(0) == 'i'){ // all image lines start with 'i'
			ImageParams currentParams;
			
			this->imageLines.push_back(currentLine);
			
			std::stringstream currentLineStream;
			currentLineStream << currentLine;
			cout << "processing line " << currentLineStream.str() << endl;
			while(std::getline(currentLineStream, currentToken, ' ')){ // get all whitespace-delimited items
				//std::cout << "item: |" << currentToken << "|" << std::endl;
				if (currentToken.length() > 0) {
				
					//let's make it some kind of state machine. It's a parser, after all.
					switch(currentToken.at(0)){
					case 'w':
						currentParams.w = atoi(currentToken.substr(1).c_str());
						break;
						
					case 'h':
						currentParams.h = atoi(currentToken.substr(1).c_str());
						break;
						
					case 'f':
						currentParams.f = atof(currentToken.substr(1).c_str());
						break;
						
					case 'E':
						switch(currentToken.at(1)){
						case 'b':
							currentParams.Eb = atof(currentToken.substr(2).c_str());
							break;
							
						case 'e':
							currentParams.Eev = atof(currentToken.substr(3).c_str());
							break;
							
						case 'r':
							currentParams.Er = atof(currentToken.substr(2).c_str());
							break;
						
						}
						break;
						
					case 'R':
						switch(currentToken.at(1)){
						case 'a':
							currentParams.Ra = atof(currentToken.substr(2).c_str());
							break;
							
						case 'b':
							currentParams.Rb = atof(currentToken.substr(2).c_str());
							break;
							
						case 'c':
							currentParams.Rc = atof(currentToken.substr(2).c_str());
							break;
							
						case 'd':
							currentParams.Rd = atof(currentToken.substr(2).c_str());
							break;
								
						case 'e':
							currentParams.Re = atof(currentToken.substr(2).c_str());
							break;
						}
						break;
						
					case 'V':
						switch(currentToken.at(1)){
						case 'a':
							currentParams.Va = atof(currentToken.substr(2).c_str());
							break;
							
						case 'b':
							currentParams.Vb = atof(currentToken.substr(2).c_str());
							break;
							
						case 'c':
							currentParams.Vc = atof(currentToken.substr(2).c_str());
							break;
							
						case 'd':
							currentParams.Vd = atof(currentToken.substr(2).c_str());
							break;
								
						case 'x':
							currentParams.Vx = atof(currentToken.substr(2).c_str());
							break;
							
						case 'y':
							currentParams.Vy = atof(currentToken.substr(2).c_str());
							break;
							
						case 'm':
							currentParams.Vm = atof(currentToken.substr(2).c_str());
							break;
						}
						break;
						
					case 'a':
						currentParams.a = atof(currentToken.substr(1).c_str());
						break;
						
					case 'b':
						currentParams.b = atof(currentToken.substr(1).c_str());
						break;
							
					case 'c':
						currentParams.c = atof(currentToken.substr(1).c_str());
						break;
						
					case 'd':
						currentParams.d = atof(currentToken.substr(1).c_str());
						break;
						
					case 'e':
						currentParams.e = atof(currentToken.substr(1).c_str());
						break;
						
					case 'g':
						currentParams.g = atof(currentToken.substr(1).c_str());
						break;
						
					case 'p':
						currentParams.p = atof(currentToken.substr(1).c_str());
						break;
						
					case 'r':
						currentParams.r = atof(currentToken.substr(1).c_str());
						break;
						
					case 't':
						currentParams.t = atof(currentToken.substr(1).c_str());
						break;
						
					case 'v':
						currentParams.v = atof(currentToken.substr(1).c_str());
						break;
						
					case 'y':
						currentParams.y = atof(currentToken.substr(1).c_str());
						break;
						
					case 'u':
						currentParams.u = atof(currentToken.substr(1).c_str());
						break;
						
					case 'n':
						currentParams.name = currentToken.substr(2, currentToken.length() -3 );
						Output::message("file name: %s", Output::DEBUG, currentToken.substr(2, currentToken.length() -3 ).c_str());
						break;
						
					}
				}
			}
			
			imageParams.push_back(currentParams);
			this->fileNames.push_back(currentParams.name);
			
		} else {
			//std::cout << "problem with line: " << currentLine << std::endl;
		}
		
		//cout << "image name: " << currentParams.name << endl;
		
		
		
		std::getline(inputFile, currentLine);
	}
	
	while(std::getline(inputFile, currentLine)){
		if (currentLine.length() > 0 && currentLine.at(0) == 'c'){ // all control point lines start with 'c'
			std::stringstream currentLineStream;
			
			currentLineStream.str(currentLine);
			cout << "processing line " << currentLineStream.str() << endl;
			
			Features::FeaturePair currentPair;
			
			currentPair.left.centerVal  = 0;
			currentPair.right.centerVal = 0;
			currentPair.valid = true;
			
			while(std::getline(currentLineStream, currentToken, ' ')){ // get all whitespace-delimited items
				if (currentToken.length() > 0) {
					switch(currentToken.at(0)){
					case 'c':
						//disregard
						break;
					case 'n':
						currentPair.leftImageID = atoi(currentToken.substr(1).c_str());
						break;
					case 'N':
						currentPair.rightImageID = atoi(currentToken.substr(1).c_str());
						break;
					case 'x':
						currentPair.left.x = atoi(currentToken.substr(1).c_str());
						break;
					case 'y':
						currentPair.left.y = atoi(currentToken.substr(1).c_str());
						break;
					case 'X':
						currentPair.right.x = atoi(currentToken.substr(1).c_str());
						break;
					case 'Y':
						currentPair.right.y = atoi(currentToken.substr(1).c_str());
						break;
					case 't':
						currentPair.id = atol(currentToken.substr(1).c_str());
						break;
					default:
						Output::message("Nothing to do for token |%s|", Output::DEBUG, currentToken.c_str());
					}
				} else {
					Output::message("Token length is 0");
				}
			}
			
			//Output::message("Current pair: (%f, %f) -> (%f, %f), id: %010llu", Output::DEBUG, currentPair.left.x, currentPair.left.y, currentPair.right.x, currentPair.right.y, currentPair.id);
			
			this->featurePairs.push_back(currentPair);
		}
	}
	
//	Output::message("Parsed feature pairs: ", Output::DEBUG);
//	for (unsigned int i = 0; i < featurePairs.size(); ++i) {
//		Output::message("(%f, %f) -> (%f, %f), id: %010llu", Output::DEBUG, featurePairs[i].left.x, featurePairs[i].left.y, featurePairs[i].right.x, featurePairs[i].right.y, featurePairs[i].id);
//	}
		
	return errorCodes::SUCCESS;
}
	
std::deque<Features::FeaturePair> PTOParser::getFeaturePairs(){
	return this->featurePairs;
}

std::deque<std::string> PTOParser::getFileNames(){
	return this->fileNames;
}

std::deque<std::string> PTOParser::getImageLines(){
	return this->imageLines;
}
